package com.bestv.search.management.datasyn.spider;

import com.bestv.search.common.dataSource.DataSourceKey;
import com.bestv.search.common.dataSource.DataSourceKeyUtil;
import com.bestv.search.common.model.Info;
import com.bestv.search.common.model.NetInfo;
import com.bestv.search.common.model.uid.UID;
import com.bestv.search.common.service.InfoManager;
import com.bestv.search.common.service.NetInfoManager;
import com.bestv.search.common.util.StringConst;
import com.bestv.search.management.datasyn.spider.model.DouBanVideoInfoJSON;
import com.bestv.search.management.datasyn.spider.model.YouKuVideoInfoJSON;
import org.apache.log4j.Logger;

import java.util.*;

public class SpiderBaseInfoSyncer extends SpiderSyncer {
    private Logger logger = Logger.getLogger(SpiderBaseInfoSyncer.class);
    private NetInfoManager netInfoManager;
    private InfoManager infoManager;

    public SpiderBaseInfoSyncer() {
        super();
        netInfoManager = (NetInfoManager) context.getBean("netInfoManager");
        infoManager = (InfoManager) context.getBean("infoManager");
    }

    public void syncYouKuBaseInfo() {
        String syncMessage = null;
        try {
            status = getProgramSyncStatus(StringConst.YOUKU, 1, StringConst.BASE);
            Date syncSuccessDate = null;
            if (status != null) {
                syncSuccessDate = status.getSyncSuccessTime();
            }

            // Gets file path
            String filePath = getFileFullPath(StringConst.BASE, StringConst.YOUKU, syncSuccessDate,
                    StringConst.YOUKU_ALL_VIDEOS_FILE);
            if (filePath != null) {
                YouKuVideoInfoJSON jsonInfo = new YouKuVideoInfoJSON();
                NetInfo netInfo = new NetInfo();
                sync(netInfo, jsonInfo, filePath);
                syncMessage = "Success sync youku base info from system search_spider @" + new Date();
            } else {
                syncMessage = "Doesn't find any new youku base info in system search_spider @" + new Date();
            }
        } catch (Exception e) {
            syncMessage = "Failed sync youku base info from system search_spider @" + new Date();
            logger.error(syncMessage);
            logger.error(e);
        } finally {
            // Updates sync status
            updateSyncStatus(getSyncStatus(StringConst.YOUKU, StringConst.BASE, syncMessage));
        }
    }

    public void syncDouBanBaseInfo() {
        String syncMessage = null;
        try {
            status = getProgramSyncStatus(StringConst.DOUBAN, 1, StringConst.BASE);
            Date syncSuccessDate = null;
            if (status != null) {
                syncSuccessDate = status.getSyncSuccessTime();
            }

            // Gets file path
            String filePath = getFileFullPath(StringConst.BASE, StringConst.DOUBAN, syncSuccessDate,
                    StringConst.DOUBAN_ALL_VIDEOS_FILE);
            if (filePath != null) {
                DouBanVideoInfoJSON jsonInfo = new DouBanVideoInfoJSON();
                NetInfo netInfo = new NetInfo();
                sync(netInfo, jsonInfo, filePath);
                syncMessage = "Success sync douban base info from system search_spider @" + new Date();
            } else {
                syncMessage = "Doesn't find any new douban base info in system search_spider @" + new Date();
            }
        } catch (Exception e) {
            syncMessage = "Failed sync douban base info from system search_spider @" + new Date();
            logger.error(syncMessage);
            logger.error(e);
        } finally {
            // Updates sync status
            updateSyncStatus(getSyncStatus(StringConst.DOUBAN, StringConst.BASE, syncMessage));
        }
    }

    @SuppressWarnings("unchecked")
    @Override
    protected <T, K> T convert(K sourceObject, T destObject) {
        NetInfo netInfo = (NetInfo) destObject;
        if (sourceObject instanceof YouKuVideoInfoJSON) {
            YouKuVideoInfoJSON jsonObj = (YouKuVideoInfoJSON) sourceObject;
            netInfo.setNetId(jsonObj.getId());
            netInfo.setName(jsonObj.getName());
            netInfo.setCategory(jsonObj.getCategory());
            netInfo.setGenre(jsonObj.getGenre());
            netInfo.setArea(jsonObj.getArea());
            netInfo.setReleased(jsonObj.getReleased());
            netInfo.setDescription(jsonObj.getDescription());
            netInfo.setDirectors(jsonObj.getDirectors());
            netInfo.setScreenwriters(jsonObj.getScreenwriters());
            netInfo.setProducers(jsonObj.getProducers());
            netInfo.setStarrings(jsonObj.getStarrings());
            netInfo.setPerformers(jsonObj.getPerformers());
            netInfo.setOriginals(jsonObj.getOriginals());
            netInfo.setVoices(jsonObj.getVoices());
            netInfo.setCompleted(jsonObj.getCompleted());
            netInfo.setEpisode_count(jsonObj.getEpisode_count());
            netInfo.setEpisode_updated(jsonObj.getEpisode_updated());
            netInfo.setView_count(jsonObj.getView_count());
            netInfo.setFavorite_count(jsonObj.getFavorite_count());
            netInfo.setSource(jsonObj.getSource());
            netInfo.setYoukuScore(jsonObj.getYoukuScore());
            netInfo.setUpdateTime(new Date());
        } else if (sourceObject instanceof DouBanVideoInfoJSON) {
            DouBanVideoInfoJSON jsonObj = (DouBanVideoInfoJSON) sourceObject;
            netInfo.setNetId(jsonObj.getId());
            netInfo.setName(jsonObj.getName());
            netInfo.setOriginal_name(jsonObj.getOriginal_name());
            netInfo.setAlias_name(jsonObj.getAlias_name());
            netInfo.setDoubanScore(jsonObj.getDoubanScore());
            netInfo.setCategory(jsonObj.getCategory());
            netInfo.setUpdateTime(new Date());
        } else {
            return null;
        }
        return (T) netInfo;
    }

    @Override
    protected <T, K> void saveOrUpdateToDB(K sourceObj, List<T> list) {
        // local site code equals to local data source Key.
        String siteCode = systemCache.getLocalDataSourceKey();
        DataSourceKey key = DataSourceKeyUtil.convert(siteCode);

        List<NetInfo> netInfos = new ArrayList<NetInfo>();
        List<Map.Entry<Long, Long>> mapping = new ArrayList<Map.Entry<Long, Long>>();
        for (T dbObj : list) {
            NetInfo netInfo = (NetInfo) dbObj;
            NetInfo netInfoInDB = null;
            List<Info> infos = null;
            if (sourceObj instanceof YouKuVideoInfoJSON) {
                netInfoInDB = netInfoManager.getInfoByNetId(key, netInfo.getNetId());
                if (netInfoInDB == null) {
                    netInfoInDB = netInfo;
                    netInfoInDB.setId(new Long(UID.getUID(netInfoInDB)));
                } else {
                    netInfoInDB.setName(netInfo.getName());
                    netInfoInDB.setCategory(netInfo.getCategory());
                    netInfoInDB.setGenre(netInfo.getGenre());
                    netInfoInDB.setArea(netInfo.getArea());
                    netInfoInDB.setReleased(netInfo.getReleased());
                    netInfoInDB.setDescription(netInfo.getDescription());
                    netInfoInDB.setDirectors(netInfo.getDirectors());
                    netInfoInDB.setScreenwriters(netInfo.getScreenwriters());
                    netInfoInDB.setProducers(netInfo.getProducers());
                    netInfoInDB.setStarrings(netInfo.getStarrings());
                    netInfoInDB.setPerformers(netInfo.getPerformers());
                    netInfoInDB.setOriginals(netInfo.getOriginals());
                    netInfoInDB.setVoices(netInfo.getVoices());
                    netInfoInDB.setCompleted(netInfo.getCompleted());
                    netInfoInDB.setEpisode_count(netInfo.getEpisode_count());
                    netInfoInDB.setEpisode_updated(netInfo.getEpisode_updated());
                    netInfoInDB.setView_count(netInfo.getView_count());
                    netInfoInDB.setFavorite_count(netInfo.getFavorite_count());
                    netInfoInDB.setSource(netInfo.getSource());
                    netInfoInDB.setYoukuScore(netInfo.getYoukuScore());
                    netInfoInDB.setUpdateTime(new Date());
                }

                // Gets infos by names, but ignore info that type is "动漫", due
                // to
                // local doesn't have match p_type
                if (netInfoInDB.getCategory() != null && !netInfoInDB.getCategory().equals(StringConst.ANIME_CHINESE)) {
                    infos = infoManager.getInfoByName(key, new String[]{netInfoInDB.getName()},
                            netInfoInDB.getCategory());
                }
            } else if (sourceObj instanceof DouBanVideoInfoJSON) {
                netInfoInDB = netInfoManager.getInfoByNetId(key, netInfo.getNetId());
                if (netInfoInDB == null) {
                    netInfoInDB = netInfo;
                    netInfoInDB.setId(new Long(UID.getUID(netInfoInDB)));
                } else {
                    netInfoInDB.setName(netInfo.getName());
                    netInfoInDB.setOriginal_name(netInfo.getOriginal_name());
                    netInfoInDB.setAlias_name(netInfo.getAlias_name());
                    netInfoInDB.setDoubanScore(netInfo.getDoubanScore());
                    netInfoInDB.setCategory(netInfo.getCategory());
                    netInfoInDB.setUpdateTime(new Date());
                }

                // Generates to names array.
                List<String> names = new ArrayList<String>();
                if (netInfoInDB.getName() != null && !netInfoInDB.getName().equals(StringConst.EMPTY)) {
                    names.add(netInfoInDB.getName());
                }
                if (netInfoInDB.getOriginal_name() != null && !netInfoInDB.getOriginal_name().equals(StringConst.EMPTY)) {
                    names.add(netInfoInDB.getOriginal_name());
                }
                String aliasNameStr = netInfoInDB.getAlias_name();
                if (aliasNameStr != null && !aliasNameStr.equals(StringConst.EMPTY)
                        && !aliasNameStr.equals(StringConst.JSON_EMPTY_STR)) {
                    String[] aliasNames = aliasNameStr.substring(1, aliasNameStr.length() - 1).split(
                            StringConst.JSON_ARRAY_SPLIT_FLAG);
                    names.addAll(Arrays.asList(aliasNames));
                }

                // Gets infos by names, but ignore info that type is "动漫", due
                // to
                // local doesn't have match p_type
                if (netInfoInDB.getCategory() != null && !netInfoInDB.getCategory().equals(StringConst.ANIME_CHINESE)) {
                    infos = infoManager.getInfoByName(key, names.toArray(new String[names.size()]),
                            netInfoInDB.getCategory());
                }
            } else {
                logger.warn("Unknow source object type " + sourceObj.getClass().getName());
                return;
            }

            // adds netInfo to list for saving
            netInfos.add(netInfoInDB);

            // Add mapping reference between info and netInfo
            if (infos != null && infos.size() != 0) {
                for (Info infoInDB : infos) {
                    mapping.add(new AbstractMap.SimpleEntry<Long, Long>(infoInDB.getId(), netInfoInDB.getId()));
                }
            }
        }

        // Save infos to DB
        netInfoManager.saveOrUpdateList(key, netInfos);

        // Save mapping to DB
        netInfoManager.saveReferenceList(key, mapping);
    }
}